package com.lanjiu.lib.business.option;

import com.lanjiu.lib.utils.th.Threader;
import com.lanjiu.pro.file.BigFileHead;
import com.lanjiu.pro.file.FileContent;
import com.lanjiu.pro.file.FriendsTransmissionRequest;
import com.lanjiu.pro.file.FriendsTransmissionResponse;
import com.lanjiu.pro.file.GroupTransmissionRequest;
import com.lanjiu.pro.file.GroupTransmissionResponse;
import com.lanjiu.pro.file.OriginalPictureVideoFriendsTransmission;
import com.lanjiu.pro.file.OriginalPictureVideoGroupTransmission;
import com.lanjiu.lib.business.FileContentFactory;
import com.lanjiu.lib.business.FileTransmissionCache;
import com.lanjiu.lib.business.OriginalPictureVideoTransmissionCreator;
import com.lanjiu.lib.business.TransmissionConstant;
import com.lanjiu.lib.business.handler.FileSenderHandler;
import com.lanjiu.lib.business.listener.OnTransmissionFinishListener;
import com.lanjiu.lib.business.util.FileJCRC32;
import com.lanjiu.lib.business.util.FilePackageCheckSumResult;
import com.lanjiu.lib.utils.log.Logger;
import com.lanjiu.lib.utils.sp.SharedPreferenceHelper;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @description: 文件传输(发送者)
 * @author: Panwei
 * @date: 2019/11/2 15:37
 */
public class FileTransmissionSender {

    private FileJCRC32 mJCRC32;
    private SharedPreferenceHelper mSPHelper;
    private FileSenderHandler mFileSenderHandler;
    private ByteBuffer mByteBuffer;
    private OnTransmissionFinishListener mTransmissionFinishListener;

    private OriginalPictureVideoFriendsTransmission mFriendTransmission;
    private OriginalPictureVideoGroupTransmission mGroupTransmission;

    private FileTransmissionChannel mFileTransmissionChannel;

    public FileTransmissionSender(SharedPreferenceHelper spHelper, FileSenderHandler fileSenderHandler) {
        this.mJCRC32 = new FileJCRC32();
        this.mSPHelper = spHelper;
        this.mFileSenderHandler = fileSenderHandler;
        this.mFileTransmissionChannel = FileTransmissionChannel.get();
    }

    public void setOnTransmissionFinishListener(OnTransmissionFinishListener listener) {
        this.mTransmissionFinishListener = listener;
    }

    // 开始上传(个人)
    public void transmissionFilePersonSend(FileTransmissionCache cache, OriginalPictureVideoFriendsTransmission friend) {
        mFriendTransmission = friend;
        transmissionFileHeadSend(cache, false);
    }

    // 开始上传(群组)
    public void transmissionFileGroupSend(FileTransmissionCache cache, OriginalPictureVideoGroupTransmission group) {
        mGroupTransmission = group;
        transmissionFileHeadSend(cache, true);
    }

    // 校验(个人) 3次机会
    private FileContent verifyPersonTransmissionResponse(FileContent requestFileContent) {
        int mVerifyFailCount = 0;
        int mReconnectCount = 0;
        FriendsTransmissionRequest request;
        FriendsTransmissionResponse response;
        FilePackageCheckSumResult checkSumResult;

        do {
            if (mVerifyFailCount >= TransmissionConstant.DEFAULT_VERIFY_FAIL_COUNT) {
                if (mFileSenderHandler != null)
                    mFileSenderHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_VERIFY_FAIL, "多次校验失败");

                return null;
            }
            if (mFriendTransmission == null) {
                if (mFileSenderHandler != null)
                    mFileSenderHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_ENTITY_NULL, "传入实体为空");
                return null;
            }
            try {
                request = mJCRC32.packageCheckSumRequest(OriginalPictureVideoTransmissionCreator.merge(mFriendTransmission, requestFileContent));
                response = mFileTransmissionChannel.service().originalFriendsTransmissionUpload(request);
                checkSumResult = mJCRC32.checkSumValidateFriendsResponse(response);
                if (checkSumResult.b_result) {
                    break;
                } else {
                    mVerifyFailCount++;
                    Logger.print("结果校验失败，重新获取");
                }
            } catch (Exception e) {
                if (e.getMessage().contains("UNAVAILABLE")) {
                    mFileTransmissionChannel.reconnect();
                    Threader.sleep(500);
                    mReconnectCount++;
                    if (mReconnectCount >= 3) {
                        if (mFileSenderHandler != null)
                            mFileSenderHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_CONNECT_ERROR, "连接异常");
                        Logger.print("Error", e.getMessage());
                        return null;
                    }
                } else {
                    if (mFileSenderHandler != null)
                        mFileSenderHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_FAIL, "服务器异常");
                    Logger.print("Error", e.getMessage());
                    return null;
                }
            }
        } while (true);
        return response.getFriendsPictureVideoMessage().getFileContent();
    }

    // 校验(群组) 3次机会
    private FileContent verifyGroupTransmissionResponse(FileContent requestFileContent) {
        int mVerifyFailCount = 0;
        int mReconnectCount = 0;
        GroupTransmissionRequest request;
        GroupTransmissionResponse response;
        FilePackageCheckSumResult checkSumResult;
        do {
            if (mVerifyFailCount >= TransmissionConstant.DEFAULT_VERIFY_FAIL_COUNT) {
                if (mFileSenderHandler != null)
                    mFileSenderHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_VERIFY_FAIL, "多次校验失败");

                return null;
            }
            if (mGroupTransmission == null) {
                if (mFileSenderHandler != null)
                    mFileSenderHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_ENTITY_NULL, "传入实体为空");
                return null;
            }
            try {
                request = mJCRC32.packageCheckSumGroupRequest(OriginalPictureVideoTransmissionCreator.merge(mGroupTransmission, requestFileContent));
                response = mFileTransmissionChannel.service().originalGroupTransmissionUpload(request);
                checkSumResult = mJCRC32.checkSumValidateGroupResponse(response);
                if (checkSumResult.b_result) {
                    break;
                } else {
                    mVerifyFailCount++;
                    Logger.print("结果校验失败，重新获取");
                }
            } catch (Exception e) {
                if (e.getMessage().contains("UNAVAILABLE")) {
                    mFileTransmissionChannel.reconnect();
                    Threader.sleep(500);
                    mReconnectCount++;
                    if (mReconnectCount >= 3) {
                        if (mFileSenderHandler != null)
                            mFileSenderHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_CONNECT_ERROR, "连接异常");
                        Logger.print("Error", e.getMessage());
                        return null;
                    }
                } else {
                    if (mFileSenderHandler != null)
                        mFileSenderHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_FAIL, "服务器异常");
                    Logger.print("Error", e.getMessage());
                    return null;
                }
            }
        } while (true);
        return response.getGroupPictureVideoMessage().getFileContent();
    }

    private void transmissionFileHeadSend(FileTransmissionCache cache, boolean isGroup) {
        if (mFileSenderHandler != null)
            mFileSenderHandler.sendStartMessage();

        FileContent responseFileContentHead;
        if (isGroup)
            responseFileContentHead = verifyGroupTransmissionResponse(FileContentFactory.createUploadFileContentHead(cache.getPackageCount(), cache.getTotalLength(), cache.getClientPath()));
        else
            responseFileContentHead = verifyPersonTransmissionResponse(FileContentFactory.createUploadFileContentHead(cache.getPackageCount(), cache.getTotalLength(), cache.getClientPath()));
        if (responseFileContentHead == null) {
            if (mTransmissionFinishListener != null)
                mTransmissionFinishListener.onTransmissionFinish(cache.getClientPath());
            return;
        }
        BigFileHead bigFileHead = responseFileContentHead.getBigFileHead();
        cache.setServerPath(bigFileHead.getServerUrl());
        mSPHelper.setObject(cache.getClientPath(), cache);

        transmissionFileFragmentSend(cache, isGroup);
    }

    private void transmissionFileFragmentSend(FileTransmissionCache cache, boolean isGroup) {
        RandomAccessFile read;
        try {
            read = new RandomAccessFile(cache.getClientPath(), "r");
        } catch (FileNotFoundException e) {
            if (mFileSenderHandler != null)
                mFileSenderHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_IO_EXCEPTION, "IO异常");

            if (mTransmissionFinishListener != null)
                mTransmissionFinishListener.onTransmissionFinish(cache.getClientPath());
            Logger.print("Error", e.getMessage());
            return;
        }
        FileChannel readChannel = read.getChannel();

        long length = cache.getTotalLength();
        long position = cache.getTransmissionPosition();
        long size;
        int sendCount = cache.getTransmissionCount();
        int mSendFailCount = 0;
        while (position < length) {
            size = length - position < TransmissionConstant.FRAGMENT_LENGTH ? length - position : TransmissionConstant.FRAGMENT_LENGTH;
            clearByteBuffer();
            try {
                mByteBuffer = readChannel.map(FileChannel.MapMode.READ_ONLY, position, size);
            } catch (IOException e) {
                if (mFileSenderHandler != null)
                    mFileSenderHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_IO_EXCEPTION, "IO异常");

                closeReadNio(read, readChannel);
                if (mTransmissionFinishListener != null)
                    mTransmissionFinishListener.onTransmissionFinish(cache.getClientPath());
                Logger.print("Error", e.getMessage());
                return;
            }

            FileContent responseFileContent;
            if (isGroup)
                responseFileContent = verifyGroupTransmissionResponse(FileContentFactory.createUploadFileContentFragment(cache, mByteBuffer, size, position));
            else
                responseFileContent = verifyPersonTransmissionResponse(FileContentFactory.createUploadFileContentFragment(cache, mByteBuffer, size, position));
            if (responseFileContent == null) {
                if (mTransmissionFinishListener != null)
                    mTransmissionFinishListener.onTransmissionFinish(cache.getClientPath());
                return;
            }
            if (TransmissionConstant.FILE_FRAGMENT.equals(responseFileContent.getPackageKind())) {
                long responsePosition = responseFileContent.getBigFileFragment().getPosition();
                if (responsePosition == position) {
                    mSendFailCount++;
                    if (mSendFailCount > TransmissionConstant.DEFAULT_SEND_FAIL_COUNT) {
                        if (mFileSenderHandler != null)
                            mFileSenderHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_SEND_FAIL, "发送失败");

                        if (mTransmissionFinishListener != null)
                            mTransmissionFinishListener.onTransmissionFinish(cache.getClientPath());
                        break;
                    }
                } else {
                    Logger.print("发送成功[" + responsePosition + "]");
                    sendCount++;
                    cache.setTransmissionCount(sendCount);
                    cache.setTransmissionLength(responsePosition);
                    cache.setTransmissionPosition(position);
                    mSPHelper.setObject(cache.getClientPath(), cache);
                    position = responsePosition;
                    if (mFileSenderHandler != null)
                        mFileSenderHandler.sendProgressMessage((int) (position * 1f / length * 100));
                }
            } else if (TransmissionConstant.FILE_FOOT.equals(responseFileContent.getPackageKind())) {
                checkTransmissionFileResult(cache, responseFileContent.getBigFileFoot().getIsSuccess());
                break;
            } else {
                if (mFileSenderHandler != null)
                    mFileSenderHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_UNKNOWN_KIND, "无效操作");

                if (mTransmissionFinishListener != null)
                    mTransmissionFinishListener.onTransmissionFinish(cache.getClientPath());
            }
        }
        closeReadNio(read, readChannel);
        transmissionFileFootSend(cache, isGroup);
    }

    private void transmissionFileFootSend(FileTransmissionCache cache, boolean isGroup) {
        FileContent responseFoot;
        if (isGroup)
            responseFoot = verifyGroupTransmissionResponse(FileContentFactory.createUploadFileContentFoot(cache));
        else
            responseFoot = verifyPersonTransmissionResponse(FileContentFactory.createUploadFileContentFoot(cache));
        if (responseFoot == null) {
            if (mFileSenderHandler != null)
                mFileSenderHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_UNKNOWN_KIND, "参数异常");

            if (mTransmissionFinishListener != null)
                mTransmissionFinishListener.onTransmissionFinish(cache.getClientPath());
            return;
        }
        if (TransmissionConstant.FILE_FOOT.equals(responseFoot.getPackageKind())) {
            checkTransmissionFileResult(cache, responseFoot.getBigFileFoot().getIsSuccess());
        } else {
            if (mFileSenderHandler != null)
                mFileSenderHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_UNKNOWN_KIND, "无效操作");

            if (mTransmissionFinishListener != null)
                mTransmissionFinishListener.onTransmissionFinish(cache.getClientPath());
        }
    }

    private void checkTransmissionFileResult(FileTransmissionCache cache, boolean isSuccess) {

        Logger.print(isSuccess ? "文件发送成功" : "文件发送失败");
        mSPHelper.delete(cache.getClientPath());
        if (mFileSenderHandler != null) {
            if (isSuccess)
                mFileSenderHandler.sendCompleteMessage(cache.getServerPath());
            else
                mFileSenderHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_FAIL, "上传失败");
        }
        if (mTransmissionFinishListener != null)
            mTransmissionFinishListener.onTransmissionFinish(cache.getClientPath());
    }

    private void clearByteBuffer() {
        if (mByteBuffer != null) {
            mByteBuffer.clear();
            mByteBuffer = null;
        }
    }

    private void closeReadNio(RandomAccessFile read, FileChannel readChannel) {
        closeFileChannel(readChannel);
        closeRandomAccessFile(read);
    }

    private void closeRandomAccessFile(RandomAccessFile read) {
        try {
            if (read != null) {
                read.close();
                read = null;
            }
        } catch (IOException e) {
            Logger.print("Error", e.getMessage());
        }
    }

    private void closeFileChannel(FileChannel readChannel) {
        try {
            if (readChannel != null) {
                readChannel.close();
                readChannel = null;
            }
        } catch (IOException e) {
            Logger.print("Error", e.getMessage());
        }
    }
}
